<template>
  <div>
    <n-spin :show="resourceLoading">
      <n-alert type="error" title="StableDiffusion无法访问" v-if="!isResourceOk" style="height: 80px">
        {{ paintArtEnums.stableDiffusion_not_online }}
      </n-alert>
      <n-form v-else inline :model="storyPaintConfig" :rules="rules" ref="formRef_checkpoint">
        <n-grid :x-gap="10">
          <n-grid-item span="8">
            <n-form-item label="CHECKPOINT" path="defaultModel">
              <n-select
                  v-model:value="storyPaintConfig.defaultModel"
                  :options="modelOption"
                  @update:value="changeModel"
                  style="width: 100%"
              />
            </n-form-item>
          </n-grid-item>
          <n-grid-item :span="8">
            <n-form-item label="VAE" path="defaultVae">
              <n-select
                  :options="vaeOption"
                  v-model:value="storyPaintConfig.defaultVae"
                  @update:value="changeVae"
                  clearable
              />
            </n-form-item>
          </n-grid-item>
          <n-grid-item span="8">
            <n-form-item :label="'CLIP终止层数{'+ storyPaintConfig.defaultClipSkip+'}'" path="defaultClipSkip">
              <n-slider v-model:value="storyPaintConfig.defaultClipSkip" step="1" :min="1" :max="12"/>
            </n-form-item>
          </n-grid-item>
        </n-grid>
      </n-form>
    </n-spin>
    <n-divider style="margin-top: 0;margin-bottom: 14px;" title-placement="left">
    </n-divider>
    <n-card>
      <n-collapse>
        <n-collapse-item title="测试效果面板" name="1">
          <n-grid x-gap="10">
            <n-grid-item :span="12">
              <n-form-item :show-label="false" label="参考图片" path="negativePrompt">
                <n-card title="参考图片" bordered>
                  <template #header-extra>
                    <n-button size="small" type="warning" style="margin-left: 5px;" @click="resetImg">清除</n-button>
                  </template>
                  <n-space justify="center">
                    <div class="canvas-wrapper">
                      <img
                          ref="img2img_imgRef"
                          :style="{
                              width: canvasWidth + 'px',
                              height: canvasHeight + 'px'
                              }"
                          v-if="demoImage"
                          :src="demoImage"
                          alt=""
                          @load="handleImgLoad"/>
                    </div>
                    <n-empty description="未上传图片" v-if="!demoImage">
                      <template #extra>
                        <n-upload
                            :custom-request="customRequest"
                        >
                          <n-button>上传图片</n-button>
                        </n-upload>
                      </template>
                    </n-empty>
                  </n-space>
                </n-card>
              </n-form-item>
              <n-form-item label="测试提示词" path="prompt">
                <n-input v-model:value="demoPrompt" type="textarea" placeholder="请输入测试提示词"/>
                <n-button type="primary" style="margin-left: 5px;height: 80px;" @click="interrogate"
                          :loading="interrogatorLoading">反推关键词
                </n-button>
              </n-form-item>
              <n-button block type="primary" size="large"
                        :loading="buttonLoading" @click="paintTest" v-if="isResourceOk">测试生成效果
              </n-button>
            </n-grid-item>
            <n-grid-item :span="12">
              <n-el style="background: var(--hover-color);">
                <n-space justify="center">
                  <div class="image-container">
                    <n-image
                        class="centered-image"
                        :object-fit="'contain'"
                        :src="fileFunction.getViewFilePathByUserFileId(imageSrc)"
                    />
                  </div>
                </n-space>
              </n-el>
              <n-space style="margin-top:20px">
                <n-scrollbar x-scrollable style="max-height: 80px">
                  <div style="white-space: nowrap;">
                    <n-image v-for="pic in picList"
                             preview-disabled
                             :lazy="true"
                             :width="70"
                             size="small"
                             @click="imageSrc = pic"
                             :class="{ 'selected': pic == imageSrc }"
                             style="margin-left: 10px;"
                             :src=fileFunction.getViewFilePathByUserFileId(pic)
                    />
                  </div>
                </n-scrollbar>
              </n-space>
            </n-grid-item>
          </n-grid>
        </n-collapse-item>
      </n-collapse>
    </n-card>
<!--    <n-tabs-->
<!--        type="segment" animated style="margin-top: 5px;" v-model:value="tabActivate"-->
<!--    >-->
<!--      <n-tab-pane v-if="props.useProgrammeSetting" name="programme" tab="方案预设" display-directive="show">-->
<!--        <ProgrammeSetting engineType="SD" programmeType="VIDEO" :choseConfig="choseProgrammeConfig"></ProgrammeSetting>-->
<!--      </n-tab-pane>-->
<!--      <n-tab-pane name="setting" tab="自定义配置" display-directive="show">-->
        <n-card title="自定义配置">
          <n-form :model="storyPaintConfig" :rules="rules" ref="formRef">
            <n-grid x-gap="15">
              <n-grid-item :span="8">
                <n-form-item label="反推算法 仅支持wd14-vit-v2-git" path="defaultInterrogator">
<!--                  <n-select size="large" :options="interrogators"-->
<!--                            v-model:value="storyPaintConfig.defaultInterrogator">-->
<!--                  </n-select>-->
                  <n-input readonly v-model:value="storyPaintConfig.defaultInterrogator"></n-input>
                </n-form-item>
                <n-form-item label="预设正向提示词" path="defaultPrompt">
                  <n-input v-model:value="storyPaintConfig.defaultPrompt" type="textarea"
                           placeholder="请输入预设正向提示词"/>
                </n-form-item>
                <n-form-item label="预设反向提示词" path="defaultNegativePrompt">
                  <n-input placeholder="请输入反向提示词" type="textarea"
                           v-model:value="storyPaintConfig.defaultNegativePrompt"/>
                </n-form-item>
                <n-form-item label="图片大小" path="defaultHeight">
                  <n-input-number v-model:value="storyPaintConfig.defaultHeight" style="width: 45%; ">
                    <template #prefix>
                      高度
                    </template>
                  </n-input-number>
                  <n-input-number v-model:value="storyPaintConfig.defaultWidth" style="width: 45%;margin-left: 10px;">
                    <template #prefix>
                      宽度
                    </template>
                  </n-input-number>
                  <n-popover>
                    <template #trigger>
                      <n-button style="margin-left: 5px;" type="primary" @click="getStoryMediaInfo">尺寸</n-button>
                    </template>
                    <span>获取视频尺寸</span>
                  </n-popover>
                </n-form-item>
                <n-form-item label="尺寸放大倍数" path="defaultRepaintTimes">
                  <n-slider v-model:value="storyPaintConfig.defaultRepaintTimes" :min="0.1" :max="4" :step="0.1"/>
                </n-form-item>
              </n-grid-item>
              <n-grid-item :span="8">
                <n-form-item label="采样器" path="defaultSamplerName">
                  <n-select
                      :options="samperOptions" v-model:value="storyPaintConfig.defaultSamplerName" placeholder="请选择"
                  />
                </n-form-item>

                <n-grid x-gap="10">
                  <n-grid-item :span="12">
                    <n-form-item label="提示词相关度" path="defaultCfgScale">
                      <n-input-number v-model:value="storyPaintConfig.defaultCfgScale"/>
                    </n-form-item>
                    <n-form-item label="随机种子" path="defaultSeed">
                      <n-input-number v-model:value="storyPaintConfig.defaultSeed" style="width: 100%"/>
                      <n-button style="margin-left: 5px;" type="primary">随机</n-button>
                    </n-form-item>
                    <n-form-item label="重绘幅度" path="" v-if="!storyPaintConfig.defaultControlNet.enabled">
                      <n-input-number v-model:value="storyPaintConfig.defaultDenoisingStrength"/>
                    </n-form-item>
                    <n-form-item path="defaultRestoreFaces" label="其余设置">
                      <n-checkbox v-model:checked="storyPaintConfig.defaultRestoreFaces">
                        ADetailer脸部修复
                      </n-checkbox>
                    </n-form-item>
                  </n-grid-item>
                  <n-grid-item :span="12">
                    <n-form-item label="批次数量" path="defaultBatchSize">
                      <n-input-number v-model:value="storyPaintConfig.defaultBatchSize"/>
                    </n-form-item>
                    <n-form-item label="采样迭代步数" path="defaultSteps">
                      <n-input-number v-model:value="storyPaintConfig.defaultSteps"/>
                    </n-form-item>
                    <n-form-item label="缩放模式" v-if="!storyPaintConfig.defaultControlNet.enabled">
                      <n-select
                          :options="scaleModeOption"
                          v-model:value="storyPaintConfig.defaultResizeMode"></n-select>
                    </n-form-item>
                    <n-form-item v-if="storyPaintConfig.defaultControlNet.enabled" path="defaultEnableHr">
                      <n-checkbox v-model:checked="storyPaintConfig.defaultEnableHr">
                        高清修复
                      </n-checkbox>
                    </n-form-item>
                  </n-grid-item>
                </n-grid>
                <n-card v-if="storyPaintConfig.defaultEnableHr" :content-style="{padding: '10px 10px 10px 10px'}">
                  <n-row>
                    <n-col :span="13">
                      <n-form-item v-if="storyPaintConfig.defaultEnableHr" label="方法算法" path="defaultHrUpscaler">
                        <n-select v-model:value="storyPaintConfig.defaultHrUpscaler" :options="hrUpscalerOptions">
                        </n-select>
                      </n-form-item>
                    </n-col>
                    <n-col :span="1"></n-col>
                    <n-col :span="10">
                      <n-form-item v-if="storyPaintConfig.defaultEnableHr" label="采样步数"
                                   path="defaultHrSecondPassSteps">
                        <n-input-number v-model:value="storyPaintConfig.defaultHrSecondPassSteps" :min="1" :max="150"
                                        :step="1"/>
                      </n-form-item>
                    </n-col>
                  </n-row>
                  <n-row>
                    <n-col :span="13">
                      <n-form-item v-if="storyPaintConfig.defaultEnableHr" label="重绘幅度"
                                   path="defaultDenoisingStrength">
                        <n-input-number v-model:value="storyPaintConfig.defaultDenoisingStrength" :min="0" :max="1.0"
                                        :step="0.01"/>
                      </n-form-item>
                    </n-col>
                    <n-col :span="1"></n-col>
                    <n-col :span="10">
                      <n-form-item v-if="storyPaintConfig.defaultEnableHr" label="放大倍率" path="defaultHrScale">
                        <n-input-number v-model:value="storyPaintConfig.defaultHrScale" :min="1" :max="4" :step="0.05"/>
                      </n-form-item>
                    </n-col>
                  </n-row>
                </n-card>
              </n-grid-item>
              <n-grid-item :span="8">
                <n-scrollbar style="max-height: 600px">
                  <n-tabs type="line" animated>
                    <n-tab-pane name="Lora" tab="Lora模型" display-directive="show">
                      <n-grid x-gap="12" :cols="3">
                        <n-gi v-if="loraList.length >0" v-for="lora in loraList">
                          <n-card>
                            <template #cover>
                              <div class="image-container-lora" @contextmenu="handleContextMenu('lora', lora,$event)">
                                <n-image :src="fileFunction.getSDModelImage(lora.modelName,'lora')" class="centered-image-lora"/>
                              </div>
                            </template>
                            <n-ellipsis style="width: 100%">
                              {{ lora.modelName }}
                            </n-ellipsis>
                          </n-card>
                        </n-gi>
                      </n-grid>
                    </n-tab-pane>
                    <n-tab-pane name="T.I Embedding" tab="T.I Embedding" display-directive="show">
                      <n-grid x-gap="12" :cols="3">
                        <n-gi v-if="embeddingList.length >0" v-for="embedding in embeddingList">
                          <n-card>
                            <template #cover>
                              <div class="image-container-lora"
                                   @contextmenu="handleContextMenu('embedding' ,embedding, $event)">
                                <n-image :src="embedding.modelImage" class="centered-image-lora"/>
                              </div>
                            </template>
                            <n-ellipsis style="width: 100%">
                              {{ embedding.modelName }}
                            </n-ellipsis>
                          </n-card>
                        </n-gi>
                      </n-grid>
                    </n-tab-pane>
                  </n-tabs>
                </n-scrollbar>
                <n-dropdown
                    placement="bottom-start"
                    trigger="manual"
                    :x="x"
                    :y="y"
                    :options="loraSelectModelOption"
                    :show="showDropdown"
                    :on-clickoutside="clickOutSide"
                    @select="handleSelect"
                />
              </n-grid-item>
            </n-grid>
            <n-divider>
            </n-divider>
            <ControlNetSetting
                :resourceId="props.resourceId"
                :demoImage="demoImage"
                ref="controlNetConfigRef"
                :updateControlNetEnable="updateControlNetEnable">
            </ControlNetSetting>

            <DynamicThresholding :dynamicThresholdingConfig="storyPaintConfig.defaultDynamicThresholding">

            </DynamicThresholding>
          </n-form>
        </n-card>
<!--      </n-tab-pane>-->
<!--    </n-tabs>-->
  </div>
</template>

<script setup lang="ts">
import {nextTick, onMounted, reactive, ref, watch} from 'vue'
import {UploadCustomRequestOptions, useMessage} from 'naive-ui'
import {resourceController} from '@/api/resource/resourceController.api'
import {sdControllerApi} from "@/api/sd/sdController.api"
// @ts-ignore
import fileFunction from "@/libs/globalFunction/file"
import {stableDiffusionDict} from '@/dictionary/stableDiffusionDict'
import {storyController} from "@/api/story/story.api"
import {paintArtEnums} from "@/enums/paintArtEnums"
import ControlNetSetting from "@/components/creator/boardConfig/controlNetSetting.vue"
import DynamicThresholding from "@/components/creator/boardConfig/DynamicThresholding.vue"
import ProgrammeSetting from '@/components/creator/boardConfig/programmeSetting.vue'

// 加载资源配置Loading
const resourceLoading = ref(false)
const selectedResource = ref("")
const modelOption = ref([])
const vaeOption = ref([])
const loraList = ref([])

const formRef = ref(null)
const formRef_checkpoint = ref(null)

const controlNetConfigRef = ref(null)

const message = useMessage();
const imageSrc = ref("")
const taskStatus = ref("waiting");
const buttonLoading = ref(false)
const picList = ref([])
const embeddingList = ref([])
// 默认sizeOption
const showDropdown = ref(false)
const x = ref(0)
const y = ref(0)
const selectModel = ref(null)
const interrogators = ref([])
const interrogatorLoading = ref(false)

const samperOptions = ref([])
const modelList = ref([])
const isResourceOk = ref(true)
// 测试图片
const demoImage = ref(null) as any
const {hrUpscalerOptions, loraSelectModelOption, repaintModelOptions, scaleModeOption} = stableDiffusionDict()

const props = defineProps({
  story: {
    type: Object,
    default: () => {
      return {}
    }
  },
  resourceId: {
    type: String,
    required: true
  },
  useProgrammeSetting: {
    type: Boolean,
    default: true
  }
})

const tabActivate = ref('programme')
onMounted(() => {
  if (!props.useProgrammeSetting) {
    tabActivate.value = 'setting'
  }
})


const storyPaintConfig = ref(reactive({
  resourceId: '',
  defaultStyleId: '',
  defaultPrompt: '(masterpiece:1.4, best quality),unity 8k wallpaper,ultra detailed,beautiful and aesthetic,perfect lighting,detailed background,',
  defaultNegativePrompt: 'NSFW,paintings, sketches, lowres, normal quality, worst quality, low quality, cropped, dot, mole, ugly, grayscale, monochrome, duplicate, morbid, mutilated, missing fingers, extra fingers, too many fingers, fused fingers, mutated hands, bad hands, poorly drawn hands, poorly drawn face, poorly drawn eyebrows, bad anatomy, cloned face, long neck, extra legs, extra arms, missing arms missing legs, malformed limbs, deformed, simple background, bad proportions, disfigured, skin spots, skin blemishes, age spot, bad feet, error, text, extra digit, fewer digits, jpeg artifacts, signature, username, blurry, watermark, mask, logo',
  defaultSeed: -1,
  defaultSamplerName: 'DPM++ 2M',
  defaultBatchSize: 1,
  defaultSteps: 20,
  defaultWidth: 512,
  defaultHeight: 521,
  defaultRepaintTimes: 1,
  defaultCfgScale: 7,
  defaultModel: '',
  defaultVae: '',
  sizeOption: '',
  defaultClipSkip: 2,
  defaultRestoreFaces: false,
  defaultEnableHr: false,
  defaultHrUpscaler: 'R-ESRGAN 4x+',
  defaultHrScale: 2,
  defaultDenoisingStrength: 0.50,
  defaultHrSecondPassSteps: 8,
  defaultInterrogator: 'wd14-vit-v2-git',
  defaultRepaintModel: 'img2img',
  defaultResizeMode: '0',
  defaultControlNet: {
    image: '',
    module: 'None',
    model: 'None',
    weight: 1.0,
    resize_mode: 1,
    low_vram: false,
    processor_res: 512,
    threshold_a: null,
    threshold_b: null,
    guidance: 1,
    guidance_start: 0,
    guidance_end: 1,
    control_mode: 0,
    pixel_perfect: true,
    preProcessor: 'Canny',
    enabled: false
  },
  defaultDynamicThresholding: {
    isEnable: false,
    mimicCfgScale: 4.0,
    thresholdPercentile: 100,
    mimicMode: "Constant",
    cfgMode: "Constant",
    mimicScaleMiniNUm: 0.0,
    cfgScaleMinium: 0.0,
    powerValue: 4.0,
    scalingStartPoint: "MEAN",
    variabilityMeasure: "AD",
    interpolatePhi: 1.0,
    separateFeatureChannles: true
  }
}))

// 设置canvas宽高
const canvasWidth = ref(300)
const canvasHeight = ref(300)

const handleImgLoad = (e: any) => {
  const image = e.target;
  let image_new = new Image()
  image_new.src = image.src
  image_new.onload = function () {
    // storyPaintConfig.value.defaultWidth = image_new.width
    // storyPaintConfig.value.defaultHeight = image_new.height
    // 计算图片宽高比例
    let imgRatio = image_new.width / image_new.height
    if (image_new.width > 300
        || image_new.height > 300) {
      // 计算缩放后的宽高
      if (imgRatio > 1) {
        canvasWidth.value = 300
        canvasHeight.value = image_new.height / (image_new.width / 300)
      } else {
        // 图片比较宽
        canvasWidth.value = image_new.width / (image_new.height / 300)
        canvasHeight.value = 300
      }
    } else {
      canvasWidth.value = image_new.width
      canvasHeight.value = image_new.height
    }
  }
}


const customRequest = (uploadOption: UploadCustomRequestOptions) => {
  const reader = new FileReader();
  //@ts-ignore
  reader.readAsDataURL(uploadOption.file.file);
  console.log(uploadOption.file.file)
  reader.onloadend = () => {
    let image = new Image()
    image.src = reader.result as any
    //@ts-ignore
    demoImage.value = reader.result
  };
}

const resetImg = () => {
  demoImage.value = ''
}

const rules = {
  resourceId: {
    required: true,
    message: '请选择资源'
  },
  sizeOption: {
    required: true,
    message: '请选择尺寸信息'
  },
  // defaultModel: {
  //   required: true,
  //   message: '请选择模型'
  // },
  defaultInterrogator: {
    required: true,
    message: '请选择反推算法'
  },
  defaultWidth: {
    required: true,
    message: '请填写宽度'
  },
  defaultHeight: {
    required: true,
    message: '请填写高度'
  },
  defaultSeed: {
    required: true,
    message: '请填写种子'
  },
  defaultSamplerName: {
    required: true,
    message: '请选择采样器'
  },
  defaultBatchSize: {
    required: true,
    message: '请填写批次数量'
  },
  defaultSteps: {
    required: true,
    message: '请填写采样迭代步数'
  },
  defaultCfgScale: {
    required: true,
    message: '请填写提示词相关度'
  },
  defaultRepaintModel: {
    required: true,
    message: '请选择重绘模式'
  }
}

const demoPrompt = ref("1 girl")

const getResourceConfig = async (resouceId: string) => {
  resourceLoading.value = true
  await resourceController.getReousceConfig(resouceId)
      .then(res => {
        resourceLoading.value = false
        if (res.code === 200) {
          const stableDiffusionInfo = res.data
          if (!stableDiffusionInfo.online){
            window.$message.error(stableDiffusionInfo.message)
            return
          }


          modelOption.value = []
          vaeOption.value = []
          loraList.value = []
          res.data.modelList.forEach((item: any) => {
            // @ts-ignore
            modelOption.value.push({
              label: item.fileName,
              value: item.fileName,
              url: item.modelImage
            })
          })
          res.data.vaeList.forEach((item: any) => {
            // @ts-ignore
            vaeOption.value.push({
              label: item,
              value: item
            })
          })

          res.data.samplerList.forEach((item: any) => {
            // @ts-ignore
            samperOptions.value.push({
              label: item,
              value: item
            })
          })
          loraList.value = res.data.loraList
          embeddingList.value = res.data.embeddingList
          storyPaintConfig.value.defaultVae = res.data.selectVae
          storyPaintConfig.value.defaultModel = res.data.selectModel
        }
      }).finally(() => {
        resourceLoading.value = false
      })
}

// 选中资源后
const resourceSelect = async (value: string) => {
  selectedResource.value = value
  await getResourceConfig(value)
}

const changeModel = (value: string) => {
  const data = {
    resourceId: selectedResource.value,
    key: 'sd_model_checkpoint',
    value: value
  }
  changeOption(data)
}

const changeVae = (value: string) => {
  const data = {
    resourceId: selectedResource.value,
    key: 'sd_vae',
    value: value
  }
  changeOption(data)
}


const changeOption = (data: any) => {
  resourceLoading.value = true
  resourceController.changeOption(data).then(res => {
    if (res.code != 200) {
      message.error(res.msg);
    }
  }).catch(() => {
    message.error("切换参数失败！")
  }).finally(() => {
    resourceLoading.value = false
  })
}


const loadConfig = async (paintConfig: string, selectedResource: string) => {
  // 当前的资源是否为已选中的资源
  await resourceSelect(selectedResource)
  // 当前数据源
  storyPaintConfig.value.resourceId = selectedResource
  if (paintConfig != null && paintConfig.length > 0) {
    // 加载配置数据
    const config = JSON.parse(paintConfig)
    storyPaintConfig.value.defaultPrompt = config.defaultPrompt
    storyPaintConfig.value.defaultHeight = config.defaultHeight
    storyPaintConfig.value.defaultWidth = config.defaultWidth
    storyPaintConfig.value.defaultSeed = config.defaultSeed
    storyPaintConfig.value.defaultSamplerName = config.defaultSamplerName
    storyPaintConfig.value.defaultBatchSize = config.defaultBatchSize
    storyPaintConfig.value.defaultSteps = config.defaultSteps
    storyPaintConfig.value.defaultCfgScale = config.defaultCfgScale
    storyPaintConfig.value.defaultRestoreFaces = config.defaultRestoreFaces
    storyPaintConfig.value.defaultEnableHr = config.defaultEnableHr
    storyPaintConfig.value.defaultHrUpscaler = config.defaultHrUpscaler
    storyPaintConfig.value.defaultHrScale = config.defaultHrScale
    storyPaintConfig.value.defaultDenoisingStrength = config.defaultDenoisingStrength
    storyPaintConfig.value.defaultHrSecondPassSteps = config.defaultHrSecondPassSteps
    storyPaintConfig.value.defaultStyleId = config.defaultStyleId
    storyPaintConfig.value.defaultNegativePrompt = config.defaultNegativePrompt
    storyPaintConfig.value.defaultModel = config.defaultModel
    storyPaintConfig.value.defaultVae = config.defaultVae
    storyPaintConfig.value.sizeOption = config.sizeOption
    storyPaintConfig.value.defaultControlNet = config.defaultControlNet
    storyPaintConfig.value.defaultRepaintTimes = config.defaultRepaintTimes
    storyPaintConfig.value.defaultRepaintModel = config.defaultRepaintModel
    storyPaintConfig.value.defaultDynamicThresholding = config.defaultDynamicThresholding
    controlNetConfigRef?.value?.loadConfig(config.defaultControlNet)
  }
}

const getConfig = () => {
  if (!isResourceOk.value) {
    message.error("当前资源不可用,请选择其他资源！")
    return
  }
  return Promise.all([
    validateForm(formRef_checkpoint),
    validateForm(formRef)
  ]).then(async (results) => {
    const allValid = results.every((valid) => valid)
    if (allValid) {
      // 获取当前controlNet配置
      storyPaintConfig.value.defaultControlNet = controlNetConfigRef?.value?.getConfig()
      return storyPaintConfig.value
    }
  })
}


defineExpose({
  getConfig, loadConfig
})

const imgToImg = async () => {
  if (demoImage.value == null || demoImage.value.length == 0) {
    message.info("请上传图片！")
    return
  }

  const sdImg2ImgPrompt: SD.Img2imgInput = reactive({
    prompt: demoPrompt.value + "," + storyPaintConfig.value.defaultPrompt,
    promptEn: demoPrompt.value + "," + storyPaintConfig.value.defaultPrompt,
    negativePrompt: storyPaintConfig.value.defaultNegativePrompt,
    seed: storyPaintConfig.value.defaultSeed,
    steps: storyPaintConfig.value.defaultSteps,
    cfgScale: storyPaintConfig.value.defaultCfgScale,
    batchSize: storyPaintConfig.value.defaultBatchSize,
    width: storyPaintConfig.value.defaultWidth * storyPaintConfig.value.defaultRepaintTimes,
    height: storyPaintConfig.value.defaultHeight * storyPaintConfig.value.defaultRepaintTimes,
    samplerName: storyPaintConfig.value.defaultSamplerName,
    image: demoImage.value,
    denoisingStrength: storyPaintConfig.value.defaultDenoisingStrength,
    savePath: ''
  })

  //构建controlnet参数
  let alwaysonScript = {} as any
  if (storyPaintConfig.value.defaultDynamicThresholding.isEnable) {
    let dynamicThresholdingScript = {} as any
    dynamicThresholdingScript['args'] = [
      storyPaintConfig.value.defaultDynamicThresholding.isEnable,
      storyPaintConfig.value.defaultDynamicThresholding.mimicCfgScale,
      storyPaintConfig.value.defaultDynamicThresholding.thresholdPercentile,
      storyPaintConfig.value.defaultDynamicThresholding.mimicMode,
      storyPaintConfig.value.defaultDynamicThresholding.mimicScaleMiniNUm,
      storyPaintConfig.value.defaultDynamicThresholding.cfgMode,
      storyPaintConfig.value.defaultDynamicThresholding.cfgScaleMinium,
      storyPaintConfig.value.defaultDynamicThresholding.powerValue,
      storyPaintConfig.value.defaultDynamicThresholding.scalingStartPoint,
      storyPaintConfig.value.defaultDynamicThresholding.variabilityMeasure,
      storyPaintConfig.value.defaultDynamicThresholding.interpolatePhi,
      storyPaintConfig.value.defaultDynamicThresholding.separateFeatureChannles
    ]
    alwaysonScript['Dynamic Thresholding (CFG Scale Fix)'] = dynamicThresholdingScript
  }

  // 添加controlnet
  sdImg2ImgPrompt.alwaysonScript = alwaysonScript
  buttonLoading.value = true
  // 获取controlNet信息
  sdImg2ImgPrompt.sdResourceId = props.resourceId
  try {
    const data = await sdControllerApi.generateImg2ImgAndCheck(sdImg2ImgPrompt, 1000 * 120)
    const images = data.userFileId.split(',')
    for (let i = 0; i < images.length; i++) {
      picList.value.push(images[i])
    }
    imageSrc.value = images[0]
  } catch (e) {
    window.$message.error("出错啦！")
  } finally {
    buttonLoading.value = false
  }
}


const txt2ImgWithCanny = async () => {

  const sdTxt2ImgPrompt: SD.Txt2ImgInput = reactive({
    prompt: '',
    negativePrompt: '',
    seed: -1,
    samplerName: 'DPM++ 2M',
    batchSize: 1,
    steps: 20,
    width: 512,
    height: 512,
    promptEn: '',
    cfgScale: 7,
    savePath: '',
    restoreFaces: false,
    enableHr: false,
    hrUpscaler: 'R-ESRGAN 4x+',
    hrScale: 2.0,
    denoisingStrength: 0.5,
    hrSecondPassSteps: 8
  });
  sdTxt2ImgPrompt.prompt = demoPrompt.value + "," + storyPaintConfig.value.defaultPrompt;
  sdTxt2ImgPrompt.negativePrompt = storyPaintConfig.value.defaultNegativePrompt;
  sdTxt2ImgPrompt.seed = storyPaintConfig.value.defaultSeed;
  sdTxt2ImgPrompt.samplerName = storyPaintConfig.value.defaultSamplerName;
  sdTxt2ImgPrompt.batchSize = storyPaintConfig.value.defaultBatchSize;
  sdTxt2ImgPrompt.steps = storyPaintConfig.value.defaultSteps;
  sdTxt2ImgPrompt.sdResourceId = storyPaintConfig.value.resourceId
  // 脸部修复
  if (storyPaintConfig.value.defaultRestoreFaces) {
    sdTxt2ImgPrompt.restoreFaces = storyPaintConfig.value.defaultRestoreFaces
  }
  // 高清修复
  if (storyPaintConfig.value.defaultEnableHr) {
    sdTxt2ImgPrompt.enableHr = storyPaintConfig.value.defaultEnableHr
    sdTxt2ImgPrompt.hrUpscaler = storyPaintConfig.value.defaultHrUpscaler
    sdTxt2ImgPrompt.hrScale = storyPaintConfig.value.defaultHrScale
    sdTxt2ImgPrompt.hrSecondPassSteps = storyPaintConfig.value.defaultHrSecondPassSteps
    sdTxt2ImgPrompt.denoisingStrength = storyPaintConfig.value.defaultDenoisingStrength
  }
  sdTxt2ImgPrompt.cfgScale = storyPaintConfig.value.defaultCfgScale
  sdTxt2ImgPrompt.width = storyPaintConfig.value.defaultWidth * storyPaintConfig.value.defaultRepaintTimes
  sdTxt2ImgPrompt.height = storyPaintConfig.value.defaultHeight * storyPaintConfig.value.defaultRepaintTimes
  storyPaintConfig.value.defaultControlNet = controlNetConfigRef?.value?.getConfig()
  storyPaintConfig.value.defaultControlNet.image = demoImage.value
  //构建controlnet参数
  let alwaysonScript = {} as any
  if (storyPaintConfig.value.defaultControlNet.enabled) {
    let controlNetScript = {} as any
    controlNetScript['args'] = [storyPaintConfig.value.defaultControlNet]
    alwaysonScript['ControlNet'] = controlNetScript
  }


  if (storyPaintConfig.value.defaultDynamicThresholding.isEnable) {
    let dynamicThresholdingScript = {} as any
    dynamicThresholdingScript['args'] = [
      storyPaintConfig.value.defaultDynamicThresholding.isEnable,
      storyPaintConfig.value.defaultDynamicThresholding.mimicCfgScale,
      storyPaintConfig.value.defaultDynamicThresholding.thresholdPercentile,
      storyPaintConfig.value.defaultDynamicThresholding.mimicMode,
      storyPaintConfig.value.defaultDynamicThresholding.mimicScaleMiniNUm,
      storyPaintConfig.value.defaultDynamicThresholding.cfgMode,
      storyPaintConfig.value.defaultDynamicThresholding.cfgScaleMinium,
      storyPaintConfig.value.defaultDynamicThresholding.powerValue,
      storyPaintConfig.value.defaultDynamicThresholding.scalingStartPoint,
      storyPaintConfig.value.defaultDynamicThresholding.variabilityMeasure,
      storyPaintConfig.value.defaultDynamicThresholding.interpolatePhi,
      storyPaintConfig.value.defaultDynamicThresholding.separateFeatureChannles
    ]
    alwaysonScript['Dynamic Thresholding (CFG Scale Fix)'] = dynamicThresholdingScript
  }


  // 添加controlnet
  sdTxt2ImgPrompt.alwaysonScript = alwaysonScript
  buttonLoading.value = true;
  try {
    const data = await sdControllerApi.generateText2ImgAndCheck(sdTxt2ImgPrompt, 1000 * 120)
    const images = data.userFileId.split(',')
    for (let i = 0; i < images.length; i++) {
      picList.value.push(images[i])
    }
    imageSrc.value = images[0]
  } catch (e) {
    message.error("出错啦！")
  } finally {
    buttonLoading.value = false
  }
}

const paintTest = async () => {
  Promise.all([
    validateForm(formRef_checkpoint),
    validateForm(formRef)
  ]).then(async (results) => {
    const allValid = results.every((valid) => valid)
    if (allValid) {
      // 根据repaintModel来判断是图生图还是txt生图
      if (!storyPaintConfig.value.defaultControlNet.enabled) {
        await imgToImg()
      } else {
        await txt2ImgWithCanny()
      }
    }
  })
}

const clickOutSide = () => {
  showDropdown.value = false
}


const handleSelect = (key: string | number) => {
  showDropdown.value = false
  if (key === 'addPositive') {
    storyPaintConfig.value.defaultPrompt = storyPaintConfig.value.defaultPrompt + "," + selectModel.value.modelName
  } else if (key === 'addNegative') {
    storyPaintConfig.value.defaultNegativePrompt = storyPaintConfig.value.defaultNegativePrompt + "," + selectModel.value.modelName
  }
}


const handleContextMenu = (type: string, model: any, e: MouseEvent) => {
  e.preventDefault()
  selectModel.value = Object.assign({}, model);
  showDropdown.value = false
  if (type === 'lora') {
    selectModel.value.modelName = '<lora:' + model.modelName + ':1>'
  }
  nextTick().then(() => {
    showDropdown.value = true
    x.value = e.clientX
    y.value = e.clientY
  })
}


const interrogate = () => {
  if (demoImage.value == null || demoImage.value.length == 0) {
    message.info("请上传图片！")
    return
  }
  interrogatorLoading.value = true
  const data = {
    resourceId: props.resourceId,
    image: demoImage.value,
    model: storyPaintConfig.value.defaultInterrogator,
    threshold: 0.35
  }
  sdControllerApi.interrogate(data).then(res => {
    if (res.code === 200) {
      demoPrompt.value = res.data;
    } else {
      message.error(res.message);
    }
  }).finally(() => {
    interrogatorLoading.value = false
  })
}


const getStoryMediaInfo = () => {
  storyController.getStoryMediaInfo(props.story.id).then((res) => {
    if (res.code === 200) {
      storyPaintConfig.value.defaultWidth = res.data.width
      storyPaintConfig.value.defaultHeight = res.data.height
    }
  })
}


const validateForm = (fr: any) => {
  return new Promise((resolve) => {
    fr.value?.validate((errors) => {
      if (!errors) {
        resolve(true)
      } else {
        resolve(false)
      }
    });
  });
}

const updateControlNetEnable = (isEnable: boolean) => {
  storyPaintConfig.value.defaultControlNet.enabled = isEnable
}

// 加载配置
const choseProgrammeConfig = (programmeConfig: string) => {
  const config = JSON.parse(programmeConfig)
  storyPaintConfig.value.defaultPrompt = config.defaultPrompt
  storyPaintConfig.value.defaultHeight = config.defaultHeight
  storyPaintConfig.value.defaultWidth = config.defaultWidth
  storyPaintConfig.value.defaultSeed = config.defaultSeed
  storyPaintConfig.value.defaultSamplerName = config.defaultSamplerName
  storyPaintConfig.value.defaultBatchSize = config.defaultBatchSize
  storyPaintConfig.value.defaultSteps = config.defaultSteps
  storyPaintConfig.value.defaultCfgScale = config.defaultCfgScale
  storyPaintConfig.value.defaultRestoreFaces = config.defaultRestoreFaces
  storyPaintConfig.value.defaultEnableHr = config.defaultEnableHr
  storyPaintConfig.value.defaultHrUpscaler = config.defaultHrUpscaler
  storyPaintConfig.value.defaultHrScale = config.defaultHrScale
  storyPaintConfig.value.defaultDenoisingStrength = config.defaultDenoisingStrength
  storyPaintConfig.value.defaultHrSecondPassSteps = config.defaultHrSecondPassSteps
  storyPaintConfig.value.defaultStyleId = config.defaultStyleId
  storyPaintConfig.value.defaultNegativePrompt = config.defaultNegativePrompt
  storyPaintConfig.value.defaultModel = config.defaultModel
  storyPaintConfig.value.defaultVae = config.defaultVae
  storyPaintConfig.value.sizeOption = config.sizeOption
  storyPaintConfig.value.defaultControlNet = config.defaultControlNet
  storyPaintConfig.value.defaultRepaintTimes = config.defaultRepaintTimes
  storyPaintConfig.value.defaultRepaintModel = config.defaultRepaintModel
  storyPaintConfig.value.defaultDynamicThresholding = config.defaultDynamicThresholding
  controlNetConfigRef?.value?.loadConfig(config.defaultControlNet)
  tabActivate.value = 'setting'
  window.$message.success("加载配置成功！")
}

</script>
<style scoped>

.image-container {
  height: 500px; /* 设置容器的固定高度 */
  display: flex; /* 使用Flex布局 */
  align-items: center; /* 垂直居中 */
  justify-content: center; /* 水平居中 */
}

.centered-image {
  max-height: 100%; /* 图片的最大高度为容器高度，宽度会自动适应宽高比例 */
  max-width: 100%; /* 图片的最大宽度为容器宽度，高度会自动适应宽高比例 */
}

.image-container-lora {
  height: 150px; /* 设置容器的固定高度 */
  display: flex; /* 使用Flex布局 */
  align-items: center; /* 垂直居中 */
  justify-content: center; /* 水平居中 */
}

.centered-image-lora {
  max-height: 100%; /* 图片的最大高度为容器高度，宽度会自动适应宽高比例 */
  max-width: 100%; /* 图片的最大宽度为容器宽度，高度会自动适应宽高比例 */
}

.selected {
  border: 3px solid #8250df;
}

</style>
